The Hasura GraphQL Engine is an open-source technology that allows you to create, in a fast way, a GraphQL server over PostgreSQL. GraphQL is a popular query language for APIs. It is a readable, flexible and scalable language that is killing REST. For more information about GraphQL, you can go to its page.
In Hasura you can do a lot of things, like make any kind of GraphQL queries, create roles and permissions to allow a group of specific users to make specific queries, run serverless functions, and much more. If you want to know everything Hasura can do, you should read this Article. Also, you can read or contribute to Hasura’s code in its Github repository.
JSON Web Tokens (JWT) is an open standard used to compact secret data and create access tokens. Auth0 helps us with all related to authentication and authorization. You don’t have to worry anymore about creating a login page and the logic behind it. Also, Auth0 stores the email and the passwords of users safely. Additionally, Auth0 creates JWT tokens to authorize a user to use an application or API, or in our case to make specific queries in Hasura.
In this tutorial, we will learn to configure Auth0 and Hasura to restrict users to make some queries and keep your database more secure. We will use Auth0 to generate JWT tokens through a POST request, though we won’t create any other application to interact with Auth0 or with its login.
All code shown in this tutorial are in this Github Repository
Here you have the Hasura server with which this tutorial was made. Pass: topcoder.
To create the Hasura instance, we are guided by this quick tutorial:
https://docs.hasura.io/1.0/graphql/manual/getting-started/heroku-simple.html
After creating the instance, anyone who has the URL could access our database. To put on a password we go to the Heroku console.
Then we go to the Settings tab and then click on the Reveal Config Vars button. We add a new variable called HASURA_GRAPHQL_ADMIN_SECRET
with the value being the password that we want to put to our Hasura server.
Once added, when we enter our server Hasura will ask us for this password.
For this tutorial we will use a simple database for a billing app:
BIlling app database:
Go to the Data tab in the Hasura console.
Go to the SQL menu on the left.
Copy the SQL script in the textbox and run it.
If we go back to the GraphiQL tab, we can realize something:
At this point, to make a query you need to pass the secret password through the headers of the requests to our server. This is a big problem because the password should not be shared with anyone other than the database administrator. In Hasura, JSON Web Tokens (JWT) is used to make queries without using the password. To generate these tokens we will use Auth0.
We create an account at [Auth0] (https://auth0.com/). Then it will appear to create our Auth0 server:
The tenant domain is the entry point to our Auth0 server, so it is advisable to have it as hidden as possible. We leave it as it is and we go to the next. On this screen, we input that the account will be personal, our role and what we will do.
Once the server is created we go to the rules menu. The rules are javascript functions that are executed before creating and returning the token. They are generally used to package more data within the payload of the token. In our case, Hasura needs extra data inside the token so it can be considered valid, so we create a new empty rule:
We put Ashura rule as our rule name and put the following code in the editor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
function (user, context, callback) {
2
const namespace = "https://hasura.io/jwt/claims";
3
const userId = user.user_id;
4 context.idToken[namespace] = {
5 'x-hasura-default-role': 'trial',
6 'x-hasura-allowed-roles': ['trial', ‘user’],
7 'x-hasura-user-id': userId,
8
};
9 callback(null, user, context);
10
}
Line 1: user
saves the user information that is being logged in. context
saves the information of the current transaction, such as the token. callback
is a function used to return the variablesuser
and context
, or some error to Auth0 or the following rule.
Line 2: https: //hasura.io/jwt/claims is the header that Hasura uses to read the variables it will use.
Line 3: Get the Auth0 Id of the user.
Lines 4-8: Hasura needs three variables: x-hasura-default-role
saves the default role that the user will have if the Headerx-hasura-role
is not passed in the query requests. x-hasura-allowed-roles
saves the roles that the user can access with the Headerx-hasura-role
. x-hasura-user-id
, an id that identifies the user that in our case will be the Auth0 id. (The use of the header x-hasura-role
will be explained later).
Line 9: We return the changes made in the token, the user and no error (null value in the first parameter).
We save the rule. So far Auth0 can already generate valid tokens, but to obtain one with only a POST request (without having an application in between) we have to configure some things.
We go to the Applications menu and create a new App:
We create a Native app and give it the name we want. Once created we click on the Settings tab, we go to the end of the page and click on Show Advanced Settings, then we go to the Grant types tab, we check the option Password and we save the changes.
This grant type allows us to obtain the credentials of a user through POST requests having the username and password. For more information, you can read the [documentation] (https://auth0.com/docs/applications/reference/grant-types-available) of Auth0.
Now, we create a new user to test our configuration. We go to the User and Roles > Users menu and click the Create User button.
We create the user of our preference. In this tutorial, we create the user a@test.com with password * Test123456 *.
Now we can send a request to get a valid token.
Before generating a token and starting to use it, we have to tell Hasura the way it will validate the token.
We go to this page: https://hasura.io/jwt-config. We place Auth0 as a provider and write our Auth0 domain, then we generate our configuration. We copy the result.
We go to the Heroku console and add what we have copied as a new configuration variable called HASURA_GRAPHQL_JWT_SECRET
.
For the next step, we need the id of the application we created earlier, from here it will be called client_id. We go to the dashboard of Auth0, we go to the Applications menu, and from here we can get the client_id.
To obtain a token we use the following request:
1 2 3 4 5 6 7 8 9 10
POST https: //YOUR_AUTH0_DOMAIN/oauth/token Content - Type: application / x - www - form - urlencoded client_id = YOUR_CLIENT_ID & grant_type = http: //auth0.com/oauth/grant-type/password-realm& responseType = token id_token & scope = openid profile & realm = Username - Password - Authentication & username = EMAIL_OF_YOUR_USER & password = PASSWORD_OF_YOUR_USER
You can run an example of this request in postman:
client_id is the ID of the application we created earlier.
grant_type is the way the user will be authenticated.
responseType we place that we want the token and the id_token.
scope indicates the allowed actions.
realm indicates the database where we will consult (Username-Password-Authentication is the default).
username and password are the user’s credentials.
After executing the request, what matters to us on the response is the id_token
.
This is the token that we will use in Hasura.
We go to the Hasura console; here we deactivate the x-hasura-admin-secret
header and add a new one with theAuthorization
key. In the value, we place Bearer and the token we obtained in the previous step.
We can check the content and validity of the token by clicking on the spy button on the right of the token.
As we can see the user has the trial and user permissions and since we have not defined any for this role, we will not be able to make any query. In the Explorer we can see what queries can be made with the permissions that the token has. In our case, nothing appears to us. Let’s create some permissions.
We go to the Data tab, to the table product and the Permissions tab.
We create the trial role and only give select permission. We mark Without any check and it can only get the names of the products. We save the permissions.
We create the user role and give it the same permissions as the trial role and it can get the barcode and product names. We save the permissions.
If we return to the GraphiQL tab, we can see that in the Explorer the query to the products
table appeared and we can also see that we can only consult the name column:
1 2 3 4 5
query productQuery { product { name } }
This means that at this moment we have the trial permissions because the header x-hasura-role
is not being passed and in the token, the default is the trial role. If we want to use the user role, we place the header x-hasura-role
with value user.
And now, we can make a different query:
1 2 3 4 5 6
query productQuery { product { name bar_code } }
Auth0 is a powerful tool combined with Hasura and it is necessary, you can’t allow any user to make any query in your database. With Hasura you can create complex permissions for your tables, you just have to have a little experience. And with Auth0 rules you can do a lot of things, format the data, make requests, save more user information, etc. If you can do it in a javascript function, you can do it in an Auth0 rule.
What is Hasura?
GraphQL
Hasura GraphQL Engine
Introduction to JSON Web Tokens
Auth0 Overview
Auth0 Grant Types